iT邦幫忙

2026 iThome 鐵人賽

DAY 7
1

昨天簡單地分享了 sudo 錯誤設定導致使用者提權的方式,其中一個步驟會讓 Linux 新手一臉遲疑。

chmod u+s /tmp/rootbash

明明 Day 06 看到的內容都只有 rwx,那為什麼會有 s?這邊就要講到今天的主角-SUID / SGID。

什麼是 SUID / SGID?

在使用系統的狀況中會發生一個問題,當使用者在執行某個程序時,這個程序需要再高一點的權限才可以運作。如果這個時候就單方面拉高帳號權限,那系統的風險就會與日俱增。畢竟真的要暢行無阻,也只有 root 才做得到。因此 Linux 有開發特殊權限的設定方式,今天的主角就是 SUID / SGID。

SUID:這個特殊權限主要是讓使用者在執行程序的時候能暫時獲得該程式擁有者(Owner)的權限。
最經典的檔案就是 /usr/bin/passwd
lab-01

更改密碼這個動作,實際上是去寫入 /etc/shadow,而這個檔案的權限是 root 專屬,一般使用者連讀都讀不到。但如果為了讓大家能改密碼就把 root 權限下放給每個 user,顯然太過危險。因此透過 SUID,讓 passwd 這支程式在執行期間取得 root 身分完成寫入,既保護了系統安全,也讓每個使用者能自由更改自己的密碼。


SGID:依套用對象不同,有兩種行為。

套用在可執行檔上:使用者執行該程式時,能暫時以該程式所屬群組(Group)的身分運作,藉此存取該群組才有權限碰觸的資源。

套用在目錄上:在該目錄下新建立的檔案與子目錄,其群組會自動繼承目錄的群組,而不是建立者的預設群組。這個特性常用於多人協作的共享目錄。

看完之後,再回頭看昨天 Day 06 用的 chmod u+s /tmp/rootbash,就能理解那個 s 為什麼能幫助提權——正因為 SUID / SGID 都讓程式以「別人的身分」執行,攻擊者才會特別鎖定這類檔案作為提權管道。要盤點系統上有哪些 SUID / SGID 檔,可以用以下指令:

find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null

SUID/SGID 有合法用途,但因為它們能造成權限身分轉換,因此 cis benchmark 要求限制它們可以生效的 filesystem,並定期審查現存 SUID/SGID executable 是否真的有業務需求。接下來我們看看實作部分:

SUID 切換身分

這次我們的目的是從 user 跳到其他身分去,一樣我們先確認自己的身分,並執行以下指令把 SUID 跟 SGID 的檔案找出來

id
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null

lab-02
lab-03

我們先看看這個檔案的權限,並嘗試執行它

ls -l /opt/lab07/backup-helper
/opt/lab07/backup-helper
/opt/lab07/backup-helper /tmp

lab-04
直接執行 /opt/lab07/backup-helper 時,可以看到程式提示我們需要提供一個目錄作為參數。不過,當我們傳入 /tmp 後,終端機並沒有顯示目錄清單。它究竟做了什麼?接下來,我們使用 strings,看看執行檔中有哪些可讀的字串:

strings /opt/lab07/backup-helper

strings 可以找出檔案中的可列印字串,例如提示訊息、路徑或命令片段。這些內容能提供分析線索,但還需要搭配實際操作或原始碼,才能確認程式的行為。執行完後我們發現一件事:
lab-05
從紅框框的內容來看我們可以知道這個程式會針對目錄做 ls -la 並寫入到 /var/log/lab07/backup.log 這個檔案裏面,我們先看一下 /var/log/lab07/backup.log 是不是真的有寫入:
lab-06

好,我們確認了這支程式確實會正常運行。接著我們可以利用 command injection 的原理來做提權的動作,我們來執行以下指令:

/opt/lab07/backup-helper '; /bin/bash #'

lab-08

在 Linux 裡面 ; 的作用是讓第一個指令執行結束後,接著執行第二個指令,我們用下面的指令試試看:

whoami ; ls -l

# 是註解的意思:只要某段前面加上 #,那一段就不會被執行,一樣執行下面的指令試試看:

whoami ; #ls -l

補充一

當我們用單引號把 ; /bin/bash # 當成一個參數送進去,程式實際組出來的指令就變成:

ls -la ; /bin/bash # >> /var/log/lab07/backup.log

變成了先對當前目錄做 ls -la,接著直接呼叫 /bin/bash,而後面的 >> /var/log/lab07/backup.log 則被 # 註解掉、不會執行。透過這個方式,我們就成功切換到了 root,用下面的圖做一個整理。
lab-09

等等...好像哪裡不對勁?
補充二jpg

昨天不是才說 euid 和 ruid 不一樣時,bash 會自己降權嗎?為什麼這次不用加 -p?別急,聽我娓娓道來。
我們在使用 strings /opt/lab07/backup-helper 的時候有一個東西叫 setuid
補充3
setuid() 是讓 Process 調整「自身使用者身分」的函式,身分改變後,會影響它能執行哪些操作。官方文件是這樣說的:
補充4
當 Process 具有 CAP_SETUID 這個 capability 時,setuid(x) 除了把 euid 設成 x,也會把 ruid 和 suid 一起設成同一個 x。所以這裡呼叫 setuid(0),三個 uid 就一次全變成 0。

不過 strings 只讓我們看到 setuid 這個名字,還不能確認參數就是 0。想真正確認,可以用會印出實際參數的 ltrace

ltrace /opt/lab07/backup-helper /tmp

補充5
從輸出可以清楚看到整條路:setuid(0) = 0setgid(0) = 0 確認了參數就是 0;接著 snprintf 那行更把指令怎麼組出來的攤開來 —— 它拿 "ls -la %s >> /var/log/lab07/backup.log" 當模板,把我們傳進去的 /tmp 塞進 %s;最後 system("ls -la /tmp >> ...") 證明它真的是丟給 shell 去跑。這也回頭解釋了:為什麼我們前面塞的 ; /bin/bash # 會被當成 shell 語法執行。

(小提醒:這裡我是用 root 執行 ltrace,所以 setuid(0) 回傳 0;如果換成一般使用者去 ltrace 一顆 SUID 檔,SUID 會被核心關掉,這行會變成 setuid(0) = -1,但要看的參數一樣是 0。)

至於它真的生效、把 ruid / euid / suid 都變成 0,其實前面那個以 user 身分執行、直接拿到 uid=0 的 root shell 就已經證明了。正因為 ruid 也一起變成 0、和 euid 一致,bash 沒有理由降權,我們才不用 -p 也能輕鬆跳 root!


SGID 設定錯誤查看機敏資訊

這次我們的目的是查看/opt/lab07/vault/db.conf,我先看看有沒有什麼我們要找的資訊:

id
cat /opt/lab07/vault/db.conf
ls -l /opt/lab07/

lab-11

我們一樣嘗試用 strings 來看一下這個檔案具體目的:
lab-12

從紅框框的部分可以看到,這支程式執行時會去 cat /opt/lab07/vault/db.conf。而因為它有設定 SGID,我們執行它的時候 egid 會變成該檔案所屬的群組,剛好 db.conf 對這個群組開了讀取權,於是就讀到了原本 user 讀不到的內容。
lab-13

⚠️ 注意這裡我們沒有變成 root,只是借到了那個群組的讀取權。這也提醒我們:提權的結果不是只有「root/非 root」兩種,有時拿到的是某個群組、某個服務帳號的能力,一樣可能是攻擊路徑的一環。

以上就是第七天的內容,展示了 SUID 跟 SGID 的設定不當可以讓駭客切換成 root 或者不同身分,明天我們將利用維運工程師最愛的 Cron Job 來進行提權,我們明天見。


上一篇
Day 06|sudo 不只是管理工具:錯誤設定如何變成提權入口
系列文
我以前被社會打穿,現在輪到我研究怎麼把系統打穿:資安工程師的 30 天紅隊轉職實驗7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言